/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.painting.resources;

import com.hercules.android.receiver.AndroidReceiver;
import com.hercules.android.receiver.AndroidReceiverException;
import com.hercules.android.receiver.ApplicationConnectData;
import com.hercules.android.receiver.ApplicationData;
import com.hercules.android.receiver.LogUtil;
import com.hercules.android.receiver.ReceiverUtil;
import com.hercules.android.receiver.model.events.XREDeviceCapabilities;
import com.hercules.android.receiver.model.objects.XREApplication;
import com.hercules.android.receiver.model.objects.XREObject;
import com.hercules.android.receiver.model.objects.XREView;
import com.hercules.android.receiver.painting.PaintersUtil;
import com.hercules.android.receiver.painting.XREObjectPainterException;

import java.util.HashMap;

/**
 * Painter for {@link XREApplication} resource. It will create nested receiver using {@link XREApplication} parameters.
 * <p>
 * AndroidAssembly1 this class was added in Android Assembly 1
 * <p>
 * <b>Thread safety:</b> Not thread safe, because base class is not thread safe
 *
 * @author 7realm
 * @version 1.0
 */
public class XREApplicationPainter extends BaseXREResourcePainter {
    private AndroidReceiver childReceiver;

    /**
     * Constructor for class {@link XREApplicationPainter}.
     *
     * @param xreResource the {@link XREApplication}
     */
    public XREApplicationPainter(XREApplication xreResource) {
        super(xreResource);
    }

    /**
     * Performs initialize actions.
     *
     * @throws XREObjectPainterException if error occurs while init procedure
     */
    @SuppressWarnings("boxing")
    @Override
    public void init() throws XREObjectPainterException {
        final String methodName = "init";
        LogUtil.enter(getLogger(), this, methodName);

        try {
            PaintersUtil.checkState(getReceiver(), "receiver");
            PaintersUtil.checkState(getXREView(), "xreView");
            PaintersUtil.checkState(getAndroidView(), "androidView");

            // get application
            XREApplication application = (XREApplication) getXREResource();

            // copy device caps from parent
            XREDeviceCapabilities parentDeviceCaps = getReceiver().getApplicationConnectData().getDeviceCaps();
            XREDeviceCapabilities deviceCaps = new XREDeviceCapabilities();
            deviceCaps.setPlatform(parentDeviceCaps.getPlatform());
            deviceCaps.setPlatformVersion(parentDeviceCaps.getPlatformVersion());
            deviceCaps.setReceiverType(parentDeviceCaps.getReceiverType());
            deviceCaps.setReceiverVersion(parentDeviceCaps.getReceiverVersion());
            deviceCaps.setMimeTypes(parentDeviceCaps.getMimeTypes());
            // set dimensions to parent XREView
            deviceCaps.setNativeDimensions(parentDeviceCaps.getNativeDimensions());

            // set connect data
            ApplicationConnectData connectData = new ApplicationConnectData();
            connectData.setUrl(application.getUrl());
            connectData.setApplicationName(ReceiverUtil.getAppNameFromUrl(application.getUrl()));
            connectData.setAppParams(application.getLaunchParams());
            connectData.setDeviceCaps(deviceCaps);
            connectData.setMinimumVersion(application.getMinimumVersion());

            // set other properties of receiver
            childReceiver = new AndroidReceiver();
            childReceiver.setApplicationConnectData(connectData);
            childReceiver.setApplicationData(new ApplicationData());
            childReceiver.getApplicationData().setSessionGUID(application.getSessionGUID());
            childReceiver.getApplicationData().setCurrentCommandIndex(
                getReceiver().getApplicationConnectData().getCurrentCommandIndex());
            childReceiver.setRootView(getAndroidView());
            childReceiver.setMaxBadCommandAcceptCount(getReceiver().getMaxBadCommandAcceptCount());
            childReceiver.setOnShutdownWaitInterval(getReceiver().getOnShutdownWaitInterval());

            // set properties of parent receiver
            childReceiver.setErrorHandler(getReceiver().getErrorHandler());
            childReceiver.setCommandHandler(getReceiver().getCommandHandler());
            childReceiver.setServerConnection(getReceiver().getServerConnection());

            // add bounding of child receiver to parent receiver
            getReceiver().getApplicationData().getNestedXREApplicationViewsIdToReceiver().put(application.getId(),
                childReceiver);
            childReceiver.getApplicationData().setParentReceiver(getReceiver());
            childReceiver.getApplicationData().setParentXREApplicationView(getXREView());

            // clone current root view to XREView
            XREView rootXREView = new XREView();
            rootXREView.setId(XREObject.ID_ROOT_VIEW);
            rootXREView.setDimensions(getXREView().getDimensions());
            rootXREView.setAlpha(getXREView().getAlpha());
            rootXREView.setClip(getXREView().isClip());
            rootXREView.setAndroidXREView(getAndroidView());

            // put cloned view to elements map
            HashMap<Integer, XREObject> elementsMap = new HashMap<Integer, XREObject>();
            elementsMap.put(rootXREView.getId(), rootXREView);
            childReceiver.getApplicationData().setElementsXREIdToObject(elementsMap);

            childReceiver.connect(false);
        } catch (IllegalStateException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        } catch (AndroidReceiverException e) {
            throw LogUtil.error(getLogger(), this, methodName, new XREObjectPainterException(
                "Error occurred while connecting to child receiver.", e));
        }

        LogUtil.exit(getLogger(), this, methodName);
    }

    /**
     * Performs clean up.
     *
     * @throws XREObjectPainterException if error occurs while clean up
     */
    @SuppressWarnings("boxing")
    @Override
    public void finish() throws XREObjectPainterException {
        final String methodName = "init";
        LogUtil.enter(getLogger(), this, methodName);

        try {
            PaintersUtil.checkState(getReceiver(), "receiver");
            PaintersUtil.checkState(getXREView(), "xreView");
            PaintersUtil.checkState(getAndroidView(), "androidView");
            PaintersUtil.checkState(childReceiver, "childReceiver");

            // remove receiver from parent
            getReceiver().getApplicationData().getNestedXREApplicationViewsIdToReceiver().remove(
                getXREResource().getId());

            // shut down receiver
            childReceiver.shutdown(false);
        } catch (IllegalStateException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        } catch (AndroidReceiverException e) {
            throw LogUtil.error(getLogger(), this, methodName, new XREObjectPainterException(
                "Error occurred while shutting down child receiver.", e));
        }

        LogUtil.exit(getLogger(), this, methodName);
    }
}
